package org.example.im.server.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.im.server.pipeline.ServerInitializer;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.util.Objects;

/**
 * @author dingrui
 * @since 2022/2/10
 * @description
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class NettyServerBootstrap {

    private final NioEventLoopGroup boosGroup = new NioEventLoopGroup(1);
    private final NioEventLoopGroup workerGroup = new NioEventLoopGroup();
    private Channel channel;

    private final ServerInitializer serverInitializer;

    public void start(InetSocketAddress address) {
        try {
            ServerBootstrap b = new ServerBootstrap()
                    .group(this.boosGroup, this.workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .localAddress(address)
                    .childHandler(this.serverInitializer);
            ChannelFuture f = b
                    .bind()
                    .addListener(l -> {
                        if (l.isSuccess()) System.out.println("[S] 服务端监听端口[" + address.getPort() + "]成功");
                        else System.out.println("[S] 服务端监听端口[" + address.getPort() + "]失败");
                    })
                    .sync();
            this.channel = f.channel();
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.boosGroup.shutdownGracefully();
            this.workerGroup.shutdownGracefully();
        }
    }

    public void destroy() {
        if (Objects.isNull(this.channel)) return;
        this.channel.close();
        this.boosGroup.shutdownGracefully();
        this.workerGroup.shutdownGracefully();
    }
}
